package net.cachedb4j.dao.impl;

import java.io.Serializable;

import javax.persistence.EntityExistsException;

import net.cachedb4j.dao.BaseGenericDao;
import net.cachedb4j.dao.support.CacheJpaDaoSupport;
import net.cachedb4j.exception.database.DatabaseConnectException;
import net.cachedb4j.exception.database.DatabaseMapException;

import org.apache.log4j.Logger;
import org.crank.crud.Finder;
import org.springframework.transaction.annotation.Transactional;

public abstract class GenericDaoCacheDB<T, PK extends Serializable> extends CacheJpaDaoSupport implements BaseGenericDao<T, PK>, Finder<T>{

	protected Class<T> type = null;

	protected boolean distinct = false;

	protected Logger logger = Logger.getLogger(GenericDaoCacheDB.class);
	
	private String newSelectStatement = null;
	
	private boolean enableCache = true;

	public GenericDaoCacheDB(final Class<T> aType) {
		this.type = aType;
	}

	public GenericDaoCacheDB() {
	}

	public void setType(Class<T> type) {
		this.type = type;
	}

	public void setDistinct(boolean distinct) {
		this.distinct = distinct;
	}

	public void setNewSelectStatement(String newSelectStatement) {
		this.newSelectStatement = newSelectStatement;
	}

	public boolean isEnableCache() {
		return enableCache;
	}

	public void setEnableCache(boolean enableCache) {
		this.enableCache = enableCache;
	}

	@SuppressWarnings("unchecked")
	@Transactional
	public T persist(T entity) {
		if(isEnableCache()) {
			// TODO: store in cache, wait for database free
			try {
				return (T) persist(type, entity);
			} catch (DatabaseConnectException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (DatabaseMapException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			};
		}

		return store(entity);
	}

	@Transactional
	public T save(T entity) {
		if(isEnableCache()) {
			// TODO: store in cache, wait for cache timeout then store to database
		}
		return store(entity);
	}

	@Transactional
	public T store(T entity) {
		try {
			// TODO: the error reporting could be deferred (the entity has an ID
			// that is in the db but not in the entity manager)
			getJpaTemplate().persist(entity);
		} catch (EntityExistsException e) {
			// if the entity exists then we call merge
			return (T) getJpaTemplate().merge(entity);
		}
		return entity;
	}

}